import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.util.NoSuchElementException;

/**
 * 
 * Contains list of Inventory items
 *
 */
public class InventoryList extends BaphiList {
	
	/**
	 * Read and create a list of Inventory items from the specified file path
	 * @param fileName
	 * @param mounting - Ship or Personal
	 * @param numOpponents - Size of Opponents list
	 * @throws FileNotFoundException
	 * @throws NoSuchElementException
	 */
	public void populate(String fileName, Inventory.Mounting mounting, int numOpponents)
		throws FileNotFoundException, NoSuchElementException
	{
		readInventoryFromFile(fileName, mounting, numOpponents);
	}
	
	/**
	 * @return Inventory item
	 */
	public Inventory get(int idx)
	{
		return (Inventory) super.get(idx);
	}
	
	/**
	 * Parses a combat class string name and returns the corresponding enumerated type, or Error if no match was found
	 * @param catString
	 * @return
	 */
	private Inventory.CombatClass parseCategory(String catString)
	{
		if (catString.equalsIgnoreCase("Non-Combat"))
			return Inventory.CombatClass.NonCombat;
		else if (catString.equalsIgnoreCase("Contact"))
			return Inventory.CombatClass.Contact;
		else if (catString.equalsIgnoreCase("Projectile"))
			return Inventory.CombatClass.Projectile;
		else if (catString.equalsIgnoreCase("Special Attack"))
			return Inventory.CombatClass.SpecialAttack;
		else if (catString.equalsIgnoreCase("Armor"))
			return Inventory.CombatClass.Armor;
		else if (catString.equalsIgnoreCase("Mobility"))
			return Inventory.CombatClass.Mobility;
		else if (catString.equalsIgnoreCase("Special Defense"))
			return Inventory.CombatClass.SpecialDefense;
		else
			return Inventory.CombatClass.Error;
	}
	
	/**
	 * Parses an inventory type string and returns the corresponding enumerated type, or Error if no match was found
	 * @param itemString
	 * @return
	 */
	private Inventory.Type parseItemFlag(String itemString)
	{
		if (itemString.equalsIgnoreCase("Ability"))
			return Inventory.Type.Ability;
		else if (itemString.equalsIgnoreCase("Item"))
			return Inventory.Type.Item;
		else
			return Inventory.Type.Error;
	}
	
	/**
	 * Parses If the string is "Tradeable" then it returns true, "Non-Tradeable" returns false. Throws an exception if it's a typo.
	 * @param tradeString
	 * @return boolean
	 */
	private boolean parseTradeableFlag(String tradeString) throws NoSuchElementException
	{
		if (tradeString.equalsIgnoreCase("Tradeable"))
			return true;
		else if (tradeString.equalsIgnoreCase("Non-Tradeable"))
			return false;
		else throw new NoSuchElementException("Expected \"Tradeable\" or \"Non-Tradeable\", but found \"" + tradeString + "\"");
	}
	
	/**
	 * Reads in Inventory objects from a file.
	 * @param fileName
	 * @param mounting - Ship or Personal
	 * @param numOpponents
	 * @throws FileNotFoundException
	 * @throws NoSuchElementException
	 */
	private void readInventoryFromFile(String fileName, Inventory.Mounting mounting, int numOpponents)
		throws FileNotFoundException, NoSuchElementException
	{
		File file = new File(fileName);
		Scanner scan;
		String iName;
		String categoryName;
		Inventory.CombatClass combatClass;
		Inventory.Type type;
		boolean isTradeable;
		int[] strengths = new int[numOpponents];

		scan = new Scanner(file);
		scan.useDelimiter(",|\n");
		
		while(scan.hasNext())
		{	
			iName = scan.next();
			categoryName = scan.next();
			combatClass = parseCategory(categoryName);
			
			// Unknown combat class?
			if (combatClass == Inventory.CombatClass.Error)
				throw new java.util.NoSuchElementException(fileName + " " + iName + ": Unknown Item Category: " + categoryName);

			type = parseItemFlag(scan.next());
			isTradeable = parseTradeableFlag(scan.next());
			
			if (combatClass == Inventory.CombatClass.NonCombat)
			{
				// If it's a non-combat item we don't read the opponent strength table.
				this.add(new Inventory(iName, combatClass, mounting, type, isTradeable, null));
			}
			else
			{
				for (int i = 0; i < numOpponents; i++)
				{
					strengths[i] = scan.nextInt();
				}
				
				this.add(new Inventory(iName, combatClass, mounting, type, isTradeable, strengths));
			}
		}
		
		scan.close();
	}	
}
